﻿#include "h/ControlCAN.h"
#include "h/canlib.h"
#include "KvaserCAN.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>

#pragma comment(lib,"canlib32.lib")

KVASER_DEICE KvaserDevice[KVASER_MAX_CHANEL];
int maxChannel = KVASER_MAX_CHANEL;
VCI_ERR_INFO mErrorInfo;
LARGE_INTEGER cupFreq;
LONGLONG freqValue = 0;
#define TimerFreq 10000;
#ifdef _DEBUG
int  main()
{
    VCI_BOARD_INFO info;
    VCI_INIT_CONFIG config;
    config.Timing0 = 0x01;
    config.Timing1 = 0x1c;
    VCI_OpenDevice(KVASER_DEVICE_TYPE, 0, 0);
    VCI_ReadBoardInfo(KVASER_DEVICE_TYPE, 0, &info);
    VCI_InitCAN(KVASER_DEVICE_TYPE, 0, 0, &config);
    VCI_StartCAN(KVASER_DEVICE_TYPE, 0, 0);
    long tick = 0;
    VCI_CAN_OBJ obj[255];
    while (1)
    {
        if (tick++ > 10000000)
        {
            tick = 0;
            int count = VCI_GetReceiveNum(KVASER_DEVICE_TYPE, 0, 0);
            VCI_ReadErrInfo(KVASER_DEVICE_TYPE, 0, 0, &mErrorInfo);
            if (count > 0)
            {
                VCI_Receive(KVASER_DEVICE_TYPE, 0, 0, obj, count, 0);
            }
        }
    }
    return 0;
}
#endif
void VCI_InitializeComponent(int device = -1)
{
    if (device > -1 && device < KVASER_MAX_CHANEL)
    {
        memset(&KvaserDevice[device], 0, sizeof(KvaserDevice[device]));
        KvaserDevice[device].Handle = -1;
    }
    else
    {
        memset(&mErrorInfo, 0, sizeof(mErrorInfo));
        memset(KvaserDevice, 0, sizeof(KvaserDevice));
    }
}

DWORD VCI_ChangeErrorCodeValue(canStatus errCode, int index = -1)
{
    DWORD retCode = STATUS_ERR;
    PVCI_ERR_INFO pInfo = &mErrorInfo;
    if (index > -1 || index < KVASER_MAX_CHANEL)
    {
        P_KVASER_DEVICE device = &KvaserDevice[index];
        pInfo = &(device->ErrorInfo);
    }
    memset(pInfo, 0, sizeof(mErrorInfo));
    switch (errCode)
    {
    case canOK:
    {
        retCode = STATUS_OK;
    }break;
    case canERR_NOTFOUND:
    case canERR_NOTINITIALIZED:
    case  canERR_NOCHANNELS:
    {
        pInfo->ErrCode |= ERR_DEVICENOTEXIST;
    }
    case  canERR_DYNALOAD:
    case  canERR_DYNALIB:
    case  canERR_DYNAINIT:
    {
        pInfo->ErrCode |= ERR_LOADKERNELDLL;
    }
    case canERR_HARDWARE:
    case canERR_NOT_SUPPORTED:
    case canERR_DRIVER:
    case canERR_INVHANDLE:
    {
        pInfo->ErrCode |= ERR_DEVICEOPEN;
    }
    case canERR_TXBUFOFL:
    {
        pInfo->ErrCode |= ERR_BUFFEROVERFLOW;
    }
    default:
    {
        pInfo->ErrCode |= ERR_CMDFAILED;
    }break;
    }
    return retCode;
}

EXTERNC DWORD __stdcall VCI_OpenDevice(DWORD DeviceType, DWORD DeviceInd, DWORD Reserved)
{
    QueryPerformanceFrequency(&cupFreq);
    freqValue = cupFreq.QuadPart / TimerFreq;
    if (DeviceType == KVASER_DEVICE_TYPE)
    {
        VCI_InitializeComponent(-1);
        canInitializeLibrary();
        //printf("VCI_OpenDevice\r\n");
        canStatus status = canGetNumberOfChannels(&maxChannel);
        if (status == canOK && maxChannel > 0)
        {
            return STATUS_OK;
        }
        else
        {
            return VCI_ChangeErrorCodeValue(status, -1);
        }
    }
    else
    {
        return STATUS_ERR;
    }
}

EXTERNC DWORD __stdcall VCI_CloseDevice(DWORD DeviceType, DWORD DeviceInd)
{
    if (DeviceType == KVASER_DEVICE_TYPE)
    {
        //printf("VCI_CloseDevice\r\n");
        VCI_InitializeComponent(-1);
        canUnloadLibrary();
        return STATUS_OK;
    }
    else
    {
        return STATUS_ERR;
    }
}

EXTERNC DWORD __stdcall VCI_InitCAN(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, PVCI_INIT_CONFIG pInitConfig)
{
    if (DeviceType == KVASER_DEVICE_TYPE && CANInd < maxChannel && CANInd >= 0 && pInitConfig != NULL)
    {
        int flag = canOPEN_ACCEPT_VIRTUAL;
        int scale = 100;
        //printf("VCI_InitCAN\r\n");
        VCI_InitializeComponent(CANInd);
        P_KVASER_DEVICE device = &KvaserDevice[CANInd];
        memcpy(&device->Config, pInitConfig, sizeof(KvaserDevice[CANInd].Config));


        device->Handle = canOpenChannel(CANInd, flag);
        if (device->Handle >= NULL)
        {
            //printf("set baudrate timing0 is 0x%x, timing1 is 0x%x \r\n", (byte)pInitConfig->Timing0, (byte)pInitConfig->Timing1);
            canStatus status = canSetBusParamsC200(device->Handle, (byte)pInitConfig->Timing0, (byte)pInitConfig->Timing1);
            if (pInitConfig->Mode == 0)
            {
                status = canSetBusOutputControl(device->Handle, canDRIVER_NORMAL);
            }
            else
            {
                status = canSetBusOutputControl(device->Handle, canDRIVER_SILENT);
            }
            status = canIoCtl(device->Handle, canIOCTL_SET_TIMER_SCALE, &scale, sizeof(4));
            scale = 0;
            status = canIoCtl(device->Handle, canIOCTL_RESET_OVERRUN_COUNT, &scale, sizeof(4));
            scale = 1;
            status = canIoCtl(device->Handle, canIOCTL_SET_REPORT_ACCESS_ERRORS, &scale, sizeof(4));
           
            //status= canSetAcceptanceFilter(device->Handle, pInitConfig->AccCode, pInitConfig->AccMask, canFILTER_SET_CODE_EXT);
            return VCI_ChangeErrorCodeValue(status, CANInd);
        }
        else
        {
            return STATUS_ERR;
        }
    }
    else
    {
        return STATUS_ERR;
    }
}

EXTERNC DWORD __stdcall VCI_ReadBoardInfo(DWORD DeviceType, DWORD DeviceInd, PVCI_BOARD_INFO pInfo)
{
    if (DeviceType == KVASER_DEVICE_TYPE && pInfo != NULL)
    {
        ULONG32 tmp;
        int channel = DeviceInd;
        canGetChannelData(channel, canCHANNELDATA_DEVDESCR_ASCII, pInfo->str_hw_Type, 40);
        //printf("str_hw_Type %s \n", pInfo->str_hw_Type);

        tmp = 0;
        canGetChannelData(channel, canCHANNELDATA_CARD_SERIAL_NO, &tmp, sizeof(tmp));
        sprintf(pInfo->str_Serial_Num, "%ld", tmp);
        //printf_s(pInfo->str_Serial_Num, "%d", tmp);
        //printf("str_Serial_Num %s \n", pInfo->str_Serial_Num);

        canGetNumberOfChannels(&maxChannel);
        pInfo->can_Num = (byte)maxChannel;

        pInfo->dr_Version = canGetVersion();
        //printf("dr_Version %d \n", pInfo->dr_Version);

        tmp = 0;
        canGetChannelData(channel, canCHANNELDATA_CARD_HARDWARE_REV, &tmp, sizeof(tmp));
        pInfo->hw_Version = (tmp >> 8) & 0xFFFF;
        //printf("hw_Version %ld \n", pInfo->hw_Version);

        tmp = 0;
        canGetChannelData(channel, canCHANNELDATA_CARD_FIRMWARE_REV, &tmp, sizeof(tmp));
        pInfo->fw_Version = tmp & 0xFFFF;
        //printf("fw_Version %ld \n", pInfo->fw_Version);

        tmp = 0;
        canGetChannelData(channel, canCHANNELDATA_DLL_FILETYPE, &tmp, sizeof(tmp));
        pInfo->in_Version = tmp & 0xFFFF;
        //printf("in_Version %d \n", pInfo->in_Version);

        tmp = 0;
        canGetChannelData(channel, canCHANNELDATA_CARD_NUMBER, &tmp, sizeof(tmp));
        pInfo->irq_Num = (USHORT)tmp;
        //printf("irq_Num %d \n", pInfo->irq_Num);
        return STATUS_OK;
    }
    else
    {
        return STATUS_ERR;
    }
}

EXTERNC DWORD __stdcall VCI_ReadErrInfo(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, PVCI_ERR_INFO pErrInfo)
{
    if (DeviceType == KVASER_DEVICE_TYPE && CANInd < maxChannel && CANInd >= 0)
    {
        ////printf("read error info\r\n");
        P_KVASER_DEVICE device = &KvaserDevice[CANInd];
        if (device->Handle >= NULL && pErrInfo != NULL)
        {
            unsigned int txErr, rxErr, ovErr;
            unsigned int errCode = 0;
            unsigned  long flag = 0;
            canStatus status = canReadErrorCounters(device->Handle, &txErr, &rxErr, &ovErr);
            status = canRequestChipStatus(device->Handle);
            status = canReadStatus(device->Handle, &flag);
            if (((flag & (canSTAT_ERROR_PASSIVE | canSTAT_RESERVED_1)) > 0))
            {
                errCode |= ERR_CAN_PASSIVE;
            }
            if ((flag & canSTAT_BUS_OFF) > 0)
            {
                errCode |= ERR_CAN_BUSOFF;
            }
            if ((flag & canSTAT_ERROR_WARNING) > 0)
            {
                errCode |= ERR_CAN_ERRALARM;
            }
            if (((flag & (canSTAT_TXERR | canSTAT_RXERR)) > 0))
            {
                errCode |= ERR_CAN_BUSERR;
            }
            if ((flag & canSTAT_HW_OVERRUN) > 0)
            {
                errCode |= ERR_CAN_OVERFLOW;
            }
            if ((flag & canSTAT_SW_OVERRUN) > 0)
            {
                errCode |= ERR_BUFFEROVERFLOW;
            }
            if (status == canOK)
            {
                if (errCode == ERR_CAN_PASSIVE)
                {
                    if (device->PASSIVE_Tick % 2 == 1)
                    {
                        errCode = 0x00;
                    }
                    else if (device->PASSIVE_Tick > 3)
                    {
                        errCode = ERR_CAN_BUSERR;
                        device->PASSIVE_Tick = 0;
                        canResetBus(device->Handle);
                    }
                    device->PASSIVE_Tick++;

                }
                else
                {
                    device->PASSIVE_Tick = 0;
                }
                device->ErrorInfo.ErrCode = errCode;
                device->ErrorInfo.Passive_ErrData[1] = (BYTE)rxErr;
                device->ErrorInfo.Passive_ErrData[2] = (BYTE)txErr;
                device->ErrorInfo.ArLost_ErrData = ovErr;
                //printf("flag=0x%x ,errcode= 0x%x\r\n", flag, device->ErrorInfo.ErrCode);
                memcpy(pErrInfo, &(device->ErrorInfo), sizeof(device->ErrorInfo));
                memset(&device->ErrorInfo, 0, sizeof(device->ErrorInfo));
                return STATUS_OK;
            }
            else
            {
                return STATUS_ERR;
            }
        }
        else
        {
            return STATUS_ERR;
        }
    }
    else
    {
        if (CANInd == -1)
        {
            memcpy(pErrInfo, &mErrorInfo, sizeof(mErrorInfo));
        }
        return STATUS_ERR;
    }
}

EXTERNC DWORD __stdcall VCI_ReadCANStatus(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, PVCI_CAN_STATUS pCANStatus)
{
    if (DeviceType == KVASER_DEVICE_TYPE && CANInd < maxChannel && CANInd >= 0)
    {
        P_KVASER_DEVICE device = &KvaserDevice[CANInd];
        if (device->Handle >= NULL && pCANStatus != NULL)
        {
            memset(pCANStatus, 0, sizeof(*pCANStatus));
            //printf("read can status\r\n");
            canStatus status = canRequestChipStatus(device->Handle);
            unsigned  long flag = 0;
            status = canReadStatus(device->Handle, &flag);
            return STATUS_OK;
        }
        else
        {
            return STATUS_ERR;
        }
    }
    else
    {
        return STATUS_ERR;
    }
}

EXTERNC DWORD __stdcall VCI_GetReference(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, DWORD RefType, PVOID pData)
{
    //printf("VCI_GetReference\r\n");


    return STATUS_OK;
}

EXTERNC DWORD __stdcall VCI_SetReference(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, DWORD RefType, PVOID pData)
{

    //printf("VCI_SetReference\r\n");

    return STATUS_OK;
}

EXTERNC ULONG __stdcall VCI_GetReceiveNum(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd)
{
    if (DeviceType == KVASER_DEVICE_TYPE && CANInd < maxChannel && CANInd >= 0)
    {
        canBusStatistics stat;
        ULONG counter = 0, diff = 0;
        P_KVASER_DEVICE device = &KvaserDevice[CANInd];
        canStatus status = canRequestBusStatistics(device->Handle);
        status = canGetBusStatistics(device->Handle, &stat, sizeof(stat));
        counter = stat.stdData;
        counter += stat.stdRemote;
        counter += stat.extData;
        counter += stat.extRemote;
        //counter += stat.errFrame;
        diff = counter - device->RxCount;
        device->RxCount = counter;
        device->ErrCount = stat.errFrame;
        device->BusLoad = stat.busLoad;
        device->OverRuns = stat.overruns;
        if (diff < 0)
        {
            diff = 0;
        }
        return diff;
    }
    else
    {
        return STATUS_ERR;
    }
}

EXTERNC DWORD __stdcall VCI_ClearBuffer(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd)
{
    if (DeviceType == KVASER_DEVICE_TYPE && CANInd < maxChannel && CANInd >= 0)
    {
        //printf("VCI_ClearBuffer\r\n");

        P_KVASER_DEVICE device = &KvaserDevice[CANInd];
        if (device->Handle >= NULL)
        {
            canStatus status = canFlushReceiveQueue(device->Handle);
            status = canFlushTransmitQueue(device->Handle);
            return VCI_ChangeErrorCodeValue(status, CANInd);
        }
        else
        {
            return STATUS_ERR;
        }
    }
    else
    {
        return STATUS_ERR;
    }
}

EXTERNC DWORD __stdcall VCI_StartCAN(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd)
{
    if (DeviceType == KVASER_DEVICE_TYPE && CANInd < maxChannel && CANInd >= 0)
    {
        P_KVASER_DEVICE device = &KvaserDevice[CANInd];
        if (device->Handle >= NULL)
        {
            //printf("VCI_StartCAN\r\n");
            canBusOff(device->Handle);
            canStatus status = canBusOn(device->Handle);
          
            QueryPerformanceCounter(&device->Timer);
            return VCI_ChangeErrorCodeValue(status, CANInd);
        }
        else
        {
            return STATUS_ERR;
        }
    }
    else
    {
        return STATUS_ERR;
    }
}

EXTERNC DWORD __stdcall VCI_ResetCAN(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd)
{
    if (DeviceType == KVASER_DEVICE_TYPE && CANInd < maxChannel && CANInd >= 0)
    {
        //printf("VCI_ResetCAN\r\n");

        P_KVASER_DEVICE device = &KvaserDevice[CANInd];
        if (device->Handle != -1)
        {
            canClose(device->Handle);
            canStatus status = canResetBus(device->Handle);
            return VCI_ChangeErrorCodeValue(status, CANInd);
        }
        else
        {
            return STATUS_ERR;
        }
    }
    else
    {
        return STATUS_ERR;
    }
}

EXTERNC ULONG __stdcall VCI_Transmit(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, PVCI_CAN_OBJ pSend, ULONG Len)
{
    if (DeviceType == KVASER_DEVICE_TYPE && CANInd < maxChannel && CANInd >= 0)
    {
        P_KVASER_DEVICE device = &KvaserDevice[CANInd];
        ULONG i = 0;
        if (KvaserDevice->Handle >= NULL)
        {
            for (i = 0; i < Len;)
            {
                PVCI_CAN_OBJ obj = &pSend[i];
                unsigned int flag = canMSG_TXACK | canMSG_TXRQ;
                if (obj->ExternFlag > 0)
                {
                    flag |= canMSG_EXT;
                }
                else
                {
                    flag |= canMSG_STD;
                }
                if (obj->RemoteFlag > 0)
                {
                    flag |= canMSG_RTR;
                }
                canStatus status = canWrite(device->Handle, obj->ID, obj->Data, obj->DataLen, flag);
                if (status == canOK)
                {
                    i++;
                }
                else
                {
                    break;
                }
            }
        }
        return i;
    }
    else
    {
        return 0;
    }
}


EXTERNC ULONG __stdcall VCI_Receive(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, PVCI_CAN_OBJ pReceive, ULONG Len, INT WaitTime)
{
    if (DeviceType == KVASER_DEVICE_TYPE && CANInd < maxChannel && CANInd >= 0)
    {
        P_KVASER_DEVICE device = &KvaserDevice[CANInd];
        int i = 0;
        if (KvaserDevice->Handle >= NULL)
        {
            while (i < Len && Len > 0)
            {
                long id = 0;
                byte data[8];
                UINT32 dlc;
                UINT32 flag;
                unsigned long timer = 0;
                canStatus status = canOK;
                if (WaitTime > 0)
                {
                    status = canReadWait(device->Handle, &id, data, &dlc, &flag, &timer, WaitTime);
                }
                else
                {
                    status = canRead(device->Handle, &id, data, &dlc, &flag, &timer);
                }
                if (status == canOK)
                {
					if ((flag & canMSGERR_MASK) > 0)
                    {
                        device->ErrorInfo.Passive_ErrData[i] = data[1];
                        break;
                    }
                    else
                    {
                        LARGE_INTEGER curCount;
                        QueryPerformanceCounter(&curCount);
                        PVCI_CAN_OBJ obj = &pReceive[i];
                        memcpy(obj->Data, data, 8);
                        obj->DataLen = (BYTE)(dlc&0xFF);
						obj->TimeStamp = (UINT32)((curCount.QuadPart - device->Timer.QuadPart)/ freqValue);
                        obj->ID = id;
                        obj->TimeFlag = 1;
                        obj->ExternFlag = (flag & canMSG_EXT) > 0 ? 1 : 0;
                        obj->RemoteFlag = (flag & canMSG_RTR) > 0 ? 1 : 0;
                        i++;
                        printf("%ld\r\n", obj->TimeStamp);
                        
                    }
                }
                else if (status == canERR_NOMSG)
                {
                    break;
                }
                else
                {
                    break;
                }
            }
        }
        return i;
    }

    else
    {
        return 0;
    }
}